package com.pocket.insight.base.sql;

import com.pocket.insight.base.context.RelationToSqlContext;
import com.pocket.insight.base.mql.BaseEval;
import com.pocket.insight.base.mql.Relation;
import com.pocket.insight.base.sql.rewriter.*;
import com.pocket.insight.entity.AppParam;
import com.pocket.insight.entity.ME;

import java.sql.Timestamp;
import java.util.List;

/**
 * 描述：
 *
 * @author shuize
 * @create 2024/12/5
 */
public interface Rewriter {

    List<Rewriter> ALL_REWRITERS = List.of(new ParamAttrRewriter(), new FunctionTypeRewriter(), new PercentileRewriter(), new FirstLastRewriter(), new LikeRewriter(), new FilterRewriter(), new JsonGetRewriter(), new BasicFunctionRewriter(), new SafeMathRewriter(), new DateCompareRewriter(), new TimeFunctionRewriter(), new DateOptimizeRewriter(), new GroupKindRewriter(), new ContainNullRewriter(), new SimplifyAndOrRewriter());

    default Relation rewrite(Relation relation) {
        return relation;
    }

    default ME rewrite(ME expr) {
        return expr;
    }

    default ME rewrite(ME expr, Dialect dialect) {
        return expr;
    }

    default ME rewrite(ME expr, Dialect dialect, Timestamp nowTimestamp, AppParam.ValueMap appParamValueMap) {
        return this.rewrite(expr, dialect);
    }

    default ME rewrite(ME expr, Dialect dialect, Timestamp nowTimestamp, AppParam.ValueMap appParamValueMap, SqlEval sqlEval) {
        return this.rewrite(expr, dialect, nowTimestamp, appParamValueMap);
    }

    default ME rewriteAfter(ME expr, Dialect dialect) {
        return expr;
    }

    default ME rewriteAfter(ME expr, Dialect dialect, Timestamp nowTimestamp, AppParam.ValueMap appParamValueMap) {
        return this.rewriteAfter(expr, dialect);
    }


    static Relation applyAllRules(Relation relation) {
        if (RelationToSqlContext.getNowTimestamp() == null) {
            RelationToSqlContext.initializeShareItems();
        }
        if ((relation.fetchRunTime()).isRewritten.booleanValue()) {
            return ((relation.fetchRunTime()).resultRewritten == null) ? relation : (relation.fetchRunTime()).resultRewritten;
        }
        Relation result =
                new MongoAccumulatorRewriter()
                        .rewrite(new RelationRewriter()
                                .rewrite(new FilterSortRewriter()
                                        .rewrite(new TopNRewriter()
                                                .rewrite(new CalculateRewriter()
                                                        .rewrite(new RollupRewriter()
                                                                .rewrite(new PerceiveRewriter()
                                                                        .rewrite(new FilterJoinRewriter()
                                                                                .rewrite(new JoinOrderRewriter()
                                                                                        .rewrite(relation)
                                                                                )
                                                                        )
                                                                )
                                                        )
                                                )
                                        )
                                )
                        );
        (result.fetchRunTime()).isRewritten = Boolean.valueOf(true);
        if (!(relation.fetchRunTime()).isRewritten.booleanValue()) {
            (relation.fetchRunTime()).isRewritten = Boolean.valueOf(true);
            (relation.fetchRunTime()).resultRewritten = result;
        }
        return result;
    }

    static ME applyAllRules(ME expr, final Dialect contextDialect, final Timestamp nowTimestamp, final AppParam.ValueMap appParamValueMap, final SqlEval sqlEval) {
        expr = (new BaseEval() {
            @Override
            public ME traverse(ME expr) {
                for (Rewriter rewriter : Rewriter.ALL_REWRITERS) {
                    expr = rewriter.rewrite(expr, contextDialect, nowTimestamp, appParamValueMap, sqlEval);
                }
                expr = super.traverse(expr);
                for (Rewriter rewriter : Rewriter.ALL_REWRITERS) {
                    expr = rewriter.rewriteAfter(expr, contextDialect, nowTimestamp, appParamValueMap);
                }
                return expr;
            }
        }).traverse(expr);
        return expr;
    }

}
